package com.simple.gateway.core.session;

import cn.hutool.core.util.StrUtil;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.simple.gateway.common.interfaces.GatewayAuth;
import com.simple.gateway.common.authorization.auth.TokenAuthService;
import com.simple.gateway.core.SimpleGatewayCoreConstants;
import com.simple.gateway.core.bind.IGenericReference;
import com.simple.gateway.core.bind.MapperRegistry;
import com.simple.gateway.core.datasource.Connection;
import com.simple.gateway.core.executor.Executor;
import com.simple.gateway.core.executor.SimpleExecutor;
import com.simple.gateway.core.mapping.HttpStatement;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.rpc.service.GenericService;

import java.util.HashMap;
import java.util.Map;

/**
 * 项目: simple-gateway-core
 *
 * 功能描述: 配置中心
 *
 * @author: WuChengXing
 *
 * @create: 2023-08-02 15:34
 **/
public class Configuration {

    /**
     * 网关 Netty 服务端口
     */
    private int port = SimpleGatewayCoreConstants.DEFAULT_GATEWAY_SERVER_PORT;

    /**
     * 地址
     */
    private String hostname = SimpleGatewayCoreConstants.DEFAULT_GATEWAY_SERVER_HOST;

    /**
     * 网关 Netty 服务线程数配置
     */
    private int bossNThreads = SimpleGatewayCoreConstants.DEFAULT_BOSS_N_THREADS;
    private int workNThreads = SimpleGatewayCoreConstants.DEFAULT_WORK_N_THREADS;

    private final MapperRegistry mapperRegistry = new MapperRegistry(this);

    /**
     * RPC 应用服务配置项 simple-gateway-test
     */
    private final Map<String, ApplicationConfig> applicationConfigMap = new HashMap<>(32);

    /**
     * 所有http的缓存
     */
    private final Map<String, HttpStatement> httpStatements = new HashMap<>(32);

    /**
     * RPC 注册中心配置项 zookeeper://127.0.0.1:2181
     */
    private final Map<String, RegistryConfig> registryConfigMap = new HashMap<>(32);

    /**
     * RPC 泛化服务配置项 com.simple.gateway.test.provider.rpc.IActivityBooth
     */
    private final Map<String, ReferenceConfig<GenericService>> referenceConfigMap = new HashMap<>(32);

    /**
     * 数据源配置
     */
    private final Map<String, DruidDataSource> datasourceConfigMap = new HashMap<>(2);

    /**
     * 授权服务
     */
    private final GatewayAuth auth = new TokenAuthService();

    public Configuration() {

    }

    public synchronized void registryDataSource(String applicationName, String jdbc, String extension) {
        if (StrUtil.hasBlank(applicationName, jdbc, extension)) {
            return;
        }
        JSONObject jsonObject = JSON.parseObject(extension);
        String dbName = (String) jsonObject.get(SimpleGatewayCoreConstants.DB_NAME_FIELD);
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUrl(jdbc + "/" + dbName);
        druidDataSource.setUsername((String) jsonObject.get(SimpleGatewayCoreConstants.DB_USERNAME_FIELD));
        druidDataSource.setPassword((String) jsonObject.get(SimpleGatewayCoreConstants.DB_PASSWORD_FIELD));
        datasourceConfigMap.put(applicationName, druidDataSource);
    }

    public synchronized void registryConfig(String applicationName, String address, String interfaceName, String version) {
        if (applicationConfigMap.get(applicationName) == null) {
            ApplicationConfig application = new ApplicationConfig();
            application.setName(applicationName);
            application.setQosEnable(false);
            applicationConfigMap.put(applicationName, application);
        }

        if (registryConfigMap.get(applicationName) == null) {
            RegistryConfig registry = new RegistryConfig();
            registry.setAddress(address);
            registry.setRegister(false);
            registryConfigMap.put(applicationName, registry);
        }

        if (referenceConfigMap.get(interfaceName) == null) {
            ReferenceConfig<GenericService> reference = new ReferenceConfig<>();
            reference.setInterface(interfaceName);
            reference.setVersion(version);
            reference.setGeneric("true");
            referenceConfigMap.put(interfaceName, reference);
        }
    }

    public ApplicationConfig getApplicationConfig(String applicationName) {
        return applicationConfigMap.get(applicationName);
    }

    public RegistryConfig getRegistryConfig(String applicationName) {
        return registryConfigMap.get(applicationName);
    }

    public ReferenceConfig<GenericService> getReferenceConfig(String interfaceName) {
        return referenceConfigMap.get(interfaceName);
    }

    public DruidDataSource getDataSource(String applicationName) {
        return datasourceConfigMap.get(applicationName);
    }

    public void addMapper(HttpStatement httpStatement) {
        mapperRegistry.addMapper(httpStatement);
    }

    public IGenericReference getMapper(String uri, GatewaySession gatewaySession) {
        return mapperRegistry.getMapper(uri, gatewaySession);
    }

    public void addHttpStatement(HttpStatement httpStatement) {
        httpStatements.put(httpStatement.getUri(), httpStatement);
    }

    public HttpStatement getHttpStatement(String uri) {
        return httpStatements.get(uri);
    }

    public Executor newExecutor(Connection connection) {
        return new SimpleExecutor(this, connection);
    }

    public boolean authValidate(String uId, String token) {
        //return auth.validate(uId, token);
        return false;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public int getBossNThreads() {
        return bossNThreads;
    }

    public void setBossNThreads(int bossNThreads) {
        this.bossNThreads = bossNThreads;
    }

    public int getWorkNThreads() {
        return workNThreads;
    }

    public void setWorkNThreads(int workNThreads) {
        this.workNThreads = workNThreads;
    }

    public String getHostname() {
        return hostname;
    }

    public void setHostname(String hostname) {
        this.hostname = hostname;
    }
}
